package com.teamfractal.fracdustry.common.container.Machines;

import com.teamfractal.fracdustry.common.block.impl.machines.FDElectricFurnaceBlock;
import com.teamfractal.fracdustry.common.container.datasync.SimpleArray;
import com.teamfractal.fracdustry.common.container.init.FDContainers;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.inventory.ContainerData;
import net.minecraft.world.inventory.ContainerLevelAccess;
import net.minecraft.world.inventory.Slot;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.SlotItemHandler;
import net.minecraftforge.items.wrapper.InvWrapper;

import javax.annotation.Nonnull;

//Thank you mcjty!

@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD)
public class FDElectricFurnaceContainer extends AbstractContainerMenu {

    private final BlockEntity blockEntity;
    private final Player playerEntity;
    private final IItemHandler playerInventory;
    private final SimpleArray processNow;
    private final SimpleArray processTotal;
    private final SimpleArray currentEnergy;
    private final SimpleArray maxEnergy;

    //introduce intArray to pass NBT data of burning time
    public FDElectricFurnaceContainer(int windowId, Level world, BlockPos pos, Inventory playerInventory, Player player, SimpleArray processNow, SimpleArray processTotal, SimpleArray currentEnergy, SimpleArray maxEnergy) {
        super(FDContainers.containerElectricFurnace.get(), windowId);
        blockEntity = world.getBlockEntity(pos);
        this.playerEntity = player;
        this.playerInventory = new InvWrapper(playerInventory);
        this.processNow = processNow;
        this.processTotal = processTotal;
        this.currentEnergy = currentEnergy;
        this.maxEnergy = maxEnergy;

        addDataSlots(this.processNow);
        addDataSlots(this.processTotal);
        addDataSlots(this.currentEnergy);
        addDataSlots(this.maxEnergy);

        if (blockEntity != null) {
            blockEntity.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, Direction.UP).ifPresent(h -> {
                addSlot(new SlotItemHandler(h, 0, 52, 33));
                addSlot(new SlotItemHandler(h, 1, 109, 33));
            });
        }
        layoutPlayerInventorySlots(8, 77);
    }


    public boolean getPowered() {
        return this.blockEntity.getBlockState().getValue(BlockStateProperties.POWERED);
    }

    @Override
    public boolean stillValid(@Nonnull Player playerIn) {
        return stillValid(ContainerLevelAccess.create(blockEntity.getLevel(), blockEntity.getBlockPos()), playerEntity, FDElectricFurnaceBlock.BLOCK);
    }

    //QuickMoveStack is probably what happened when you press Shift and left-click on an itemstack
    //28 & 37 probably means when you shift&left-click a non-fuel item in hotbar, it will be moved into player's backpack inventory,
    //instead of the thermal generator's Slot#0
    @Nonnull
    @Override
    public ItemStack quickMoveStack(@Nonnull Player playerIn, int index) {
        ItemStack itemstack = ItemStack.EMPTY;
        Slot slot = this.slots.get(index);
        if (slot.hasItem()) {
            ItemStack stack = slot.getItem();
            itemstack = stack.copy();
            if (index == 0) {
                if (!this.moveItemStackTo(stack, 1, 37, true)) {
                    return ItemStack.EMPTY;
                }
                slot.onQuickCraft(stack, itemstack);
            }else if(index == 1){
                if (!this.moveItemStackTo(stack, 2, 37, true)) {
                    return ItemStack.EMPTY;
                }
                slot.onQuickCraft(stack, itemstack);
            } else {
                //Should Check Item
                if (true) {
                    if (!this.moveItemStackTo(stack, 0, 1, false)) {
                        return ItemStack.EMPTY;
                    }
                } else if (index < 28) {
                    if (!this.moveItemStackTo(stack, 28, 37, false)) {
                        return ItemStack.EMPTY;
                    }
                } else if (index < 37 && !this.moveItemStackTo(stack, 1, 28, false)) {
                    return ItemStack.EMPTY;
                }
            }

            if (stack.isEmpty()) {
                slot.set(ItemStack.EMPTY);
            } else {
                slot.setChanged();
            }

            if (stack.getCount() == itemstack.getCount()) {
                return ItemStack.EMPTY;
            }

            slot.onTake(playerIn, stack);
        }

        return itemstack;
    }

    private int addSlotRange(IItemHandler handler, int index, int x, int y, int amount, int dx) {
        for (int i = 0; i < amount; i++) {
            addSlot(new SlotItemHandler(handler, index, x, y));
            x += dx;
            index++;
        }
        return index;
    }

    private int addSlotBox(IItemHandler handler, int index, int x, int y, int horAmount, int dx, int verAmount, int dy) {
        for (int j = 0; j < verAmount; j++) {
            index = addSlotRange(handler, index, x, y, horAmount, dx);
            y += dy;
        }
        return index;
    }

    //map and overlay the player's inventory slot
    private void layoutPlayerInventorySlots(int leftCol, int topRow) {
        // Player inventory
        addSlotBox(playerInventory, 9, leftCol, topRow, 9, 18, 3, 18);

        // Hotbar
        topRow += 58;
        addSlotRange(playerInventory, 0, leftCol, topRow, 9, 18);
    }

    public ContainerData getProcessNow() {
        return processNow;
    }

    public ContainerData getProcessTotal() {
        return processTotal;
    }

    public ContainerData getCurrentEnergy() {
        return currentEnergy;
    }

    public ContainerData getMaxEnergy() {
        return maxEnergy;
    }
}

